package com.getpebble.android.bluetooth.device;

import android.os.Handler;
import android.os.HandlerThread;
import com.getpebble.android.PebbleApplication;
import com.getpebble.android.bluetooth.protocol.ProtocolMessage;
import com.getpebble.android.common.core.async.PblAsyncTask;
import com.getpebble.android.common.core.trace.Trace;
import com.getpebble.android.common.core.util.PblPreferences;
import com.getpebble.android.common.core.util.PblPreferences.PrefKey;
import com.getpebble.android.framework.util.ByteUtils;
import java.io.IOException;
import java.nio.ByteBuffer;

abstract class RemoteDeviceInputTask extends PblAsyncTask {
    private static final String TAG = RemoteDeviceInputTask.class.getSimpleName();
    private Handler mCallbacksHandler;
    private HandlerThread mCallbacksThread;
    private final PblPreferences mPrefs = new PblPreferences(PebbleApplication.getAppContext());
    private RemoteDevice mRemoteDevice = null;
    private boolean mStopRequested = false;

    abstract void onDisconnect();

    abstract void onMessageReceived(ProtocolMessage protocolMessage);

    RemoteDeviceInputTask(RemoteDevice remoteDevice) throws IllegalArgumentException {
        if (remoteDevice == null) {
            throw new IllegalArgumentException("'remoteDevice' cannot be null!");
        }
        this.mRemoteDevice = remoteDevice;
    }

    void stopInput() {
        this.mStopRequested = true;
    }

    public boolean doInBackground() {
        this.mCallbacksThread = new HandlerThread("input_callbacks_" + this.mRemoteDevice.getAddress());
        this.mCallbacksThread.start();
        this.mCallbacksHandler = new Handler(this.mCallbacksThread.getLooper());
        ByteBuffer headerBuffer = ByteBuffer.allocate(4);
        while (!this.mStopRequested) {
            int bytesRead = 0;
            do {
                boolean readSuccessful;
                int bytesReadLast = this.mRemoteDevice.readInputMessage(headerBuffer.array(), bytesRead, headerBuffer.capacity() - bytesRead);
                if (bytesReadLast > 0) {
                    readSuccessful = true;
                } else {
                    readSuccessful = false;
                }
                if (readSuccessful) {
                    bytesRead += bytesReadLast;
                }
                if (!readSuccessful) {
                    break;
                }
            } while (bytesRead < headerBuffer.capacity());
            if (!readSuccessful) {
                Trace.error(TAG, "end of input signalled, this will prevent further communications from the Pebble");
                break;
            }
            headerBuffer.position(0);
            short bodyLength = headerBuffer.getShort();
            short endpointId = headerBuffer.getShort();
            byte[] bodyBuffer = new byte[bodyLength];
            bytesRead = 0;
            do {
                bytesReadLast = this.mRemoteDevice.readInputMessage(bodyBuffer, bytesRead, bodyBuffer.length - bytesRead);
                if (bytesReadLast > 0) {
                    readSuccessful = true;
                } else {
                    readSuccessful = false;
                }
                if (readSuccessful) {
                    bytesRead += bytesReadLast;
                }
                if (!readSuccessful) {
                    break;
                }
            } while (bytesRead < bodyLength);
            if (!readSuccessful) {
                Trace.error(TAG, "end of input signalled, this will prevent further communications from the Pebble");
                break;
            }
            try {
                if (this.mPrefs.getBooleanData(PrefKey.HEX_DUMP, false)) {
                    Trace.verbose(TAG, "Received length = " + bodyLength + " data = " + ByteUtils.hexDump(headerBuffer.array()) + " " + ByteUtils.hexDump(bodyBuffer));
                }
                doMessageReceivedCallback(new ProtocolMessage(endpointId, bodyBuffer));
            } catch (IOException e) {
                Trace.error(TAG, "input problem will prevent further communications from the Pebble", e);
            }
        }
        return false;
    }

    protected void doMessageReceivedCallback(final ProtocolMessage message) {
        this.mCallbacksHandler.post(new Runnable() {
            public void run() {
                RemoteDeviceInputTask.this.onMessageReceived(message);
            }
        });
    }

    public void onTaskSuccess() {
        Trace.error(TAG, "Connection exited gracefully (should not happen)");
        onDisconnect();
        destroyCallbacksThread();
    }

    public void onTaskFailed() {
        Trace.info(TAG, "Connection exited");
        onDisconnect();
        destroyCallbacksThread();
    }

    private void destroyCallbacksThread() {
        this.mCallbacksHandler.removeCallbacksAndMessages(null);
        this.mCallbacksThread.quit();
    }
}
